package db

import (
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	appErr "lib/exception"
	"sync"
)

type Factory interface {
	GetDataSource(target string, tables ...interface{}) (*gorm.DB, appErr.Exception)
	CloseDataSource(db *gorm.DB) appErr.Exception
}

type dbFactory struct {
	DbPath string
	Db     *gorm.DB
	Tables []interface{}
}

func initialization(f *dbFactory) appErr.Exception {
	dbConfig := &gorm.Config{
		DisableForeignKeyConstraintWhenMigrating: true,
		Logger:                                   nil,
	}
	dbConn, connErr := gorm.Open(sqlite.Open(f.DbPath), dbConfig)
	if connErr != nil {
		f.Db = nil
		return connErr
	}
	f.Db = dbConn
	return nil
}

func migration(f *dbFactory) appErr.Exception {
	return f.Db.AutoMigrate(f.Tables...)
}

func (d *dbFactory) GetDataSource(target string, tables ...interface{}) (*gorm.DB, appErr.Exception) {
	d.DbPath = target
	d.Tables = tables
	if initErr := initialization(d); initErr != nil {
		return nil, initErr
	}
	if mErr := migration(d); mErr != nil {
		return nil, mErr
	}
	return d.Db, nil
}

func (d *dbFactory) CloseDataSource(db *gorm.DB) appErr.Exception {
	return nil
}

var once sync.Once
var instance Factory

func DynamicFactory() Factory {
	once.Do(func() {
		instance = &dbFactory{
			DbPath: "",
			Db:     nil,
			Tables: nil,
		}
	})
	return instance
}
